Java Blog

Since I'm very lazy in sharing my thoughts, this blog may contain very few posts - so please be patient! :-)

Mittwoch, September 27, 2006

Usage of constant values in JSP code

As JSP developer I always have been disturbed by the lack of support for static constant values. With scriptlets or runtime expressions in <%= %> tags it's none of a problem - but who still uses this kind of coding style? In times of custom tags and the expression language provided by JSP/JSF you more and more refer to objects located in some scope of your application.

Unfortunately the new expression language of JSP still does not support the use of static constant values - you still are forced to use hard-coded string literals throughout your JSPs.

At the end of last year I was working on my first real JSF project and finally found a nifty solution for this kind of problem.

I put all my application wide constants in a single "Constants" class. Then I used a ServletContextListener to put all it's public static fields via introspection in a Map in the application scope (not as JSF backing bean, but as ServletContext attribute) using the key "Constants".

    public final class Constants {

/** ID for reference from the ServletContext. */
public static final String ID = "Constants";

// other constants follow, e. g. for the example below:
public static final String TAB_DETAILS = "tabDetails";
...

/** "Cache" holding all public static fields by it's field name */
private static Map nameToValueMap = createNameToValueMap();

/**
* Puts all public static fields via introspection into the resulting Map.
* Uses the name of the field as key to reference it's in the Map.
*
* @return a Map of field names to field values of
* all public static fields of this class
*/
private static Map createNameToValueMap() {
Map result = new HashMap();
Field[] publicFields = Constants.class.getFields();
for (int i = 0; i < publicFields.length; i++) {
Field field = publicFields[i];
String name = field.getName();
try {
result.put(name, field.get(null));
} catch (Exception e) {
System.err.println("Initialization of Constants class failed!");
e.printStackTrace(System.err);
}
}
return result;
}

/**
* Gets the Map of all public static fields.
* The field name is used as key for the value of the field itself.
*
* @return the Map of all public static fields
*/
public static Map getNameToValueMap() {
return nameToValueMap;
}
}


So, as already wrote, I put the Map into an application scoped attribute using a ServletContextListener:

   ...
public void contextInitialized(ServletContextEvent event) {
ServletContext sc = event.getServletContext();
sc.setAttribute(Constants.ID, Constants.getNameToValueMap());
}
...


This way I could access all my constants in the JSPs via JSP expression language:

    ...
<c:if test="${globalView.linieTab eq Constants.TAB_DETAILS}">
...


Since the expression language allows you to reference mapped values via Map['key'] or Map.key, I could use the "dot" syntax to mimic a normal static access to the Constants classes fields.

In JSFs expression language you additionally have to use the prefix "applicationScope.", since the normal VariableResolver implementations search for a managed bean by default - which my Map clearly isn't...

    <h:inputHidden value="#{applicationScope.Constants.TAB_DETAILS}">


I hope this helps you achieve your goal of reusable constant values throughout your application.

Labels: